﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using DomainDriver.DomainModeling.DomainObjects;
using DomainDriver.DomainModeling.Queries;
using DomainDriver.DomainModeling.StorageManagers.DataSetStorage;
using DomainDriver.DomainModeling.StorageManagers.EntityFrameworkStorage;
using AutomotivePricingModel.ValueObjects.MissingValueOptions;
using ObjectRow = AutomotivePricingModel.ValueObjects.YearlyFinancialAssessments.YearlyFinancialAssessmentsDataSet.YearlyFinancialAssessmentsRow;
using NestedObjectRow = AutomotivePricingModel.ValueObjects.YearlyFinancialAssessments.YearlyFinancialAssessmentsDataSet.YearValueObservationsRow;

namespace AutomotivePricingModel.ValueObjects.YearlyFinancialAssessments
{
    public partial class YearlyFinancialAssessment : IEfEntity<Guid>, IEfStorableObject, IEfAggregate<YearlyFinancialAssessment>, IDataSetSerializable<DataSet, DataRow>
    {
        #region ADO .NET Entities Framework Storage

        public object[] EF_CombinedKey
        {
            get
            {
                object[] combined = new object[] { EF_Key };
                return combined;
            }
        }

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public Guid EF_Key
        {
            get { return m_Key; }
            set { m_Key = value; }
        }

        [Required]
        public int EF_MissingValueOption
        {
            get { return (int)m_MissingValueOption; }
            set { m_MissingValueOption = (MissingValueOptionEnum)value; }
        }

        [NotMapped]
        public ICollection<YearValueObservation> EF_YearlyObservations
        {
            get
            {
                List<YearValueObservation> observations = new List<YearValueObservation>(m_YearlyObservations.Values);
                return observations;
            }
            set
            {
                m_YearlyObservations.Clear();
                foreach (YearValueObservation observation in value)
                {
                    m_YearlyObservations.Add(observation.Year, observation);
                }
            }
        }

        [NotMapped]
        public ICollection<QuerySpecification> OverriddenQueries
        {
            get
            {
                List<QuerySpecification> overriddenQueries = new List<QuerySpecification>();
                return overriddenQueries;
            }
        }

        public bool SearchNestedAggregateValues(DbContext context, IParameterizedQuery<YearlyFinancialAssessment> query)
        {
            throw new InvalidOperationException("The specified query is not properly overridden.");
        }

        protected static readonly string YearValueObservationName = (typeof(YearValueObservation)).Name;
        public void ReadNestedAggregateValues(DbContext context, object rootQueryPredicate, Dictionary<string, object> batchReadState)
        {
            LoadNestedBatchReadState(context, rootQueryPredicate, batchReadState);

            IQueryable<YearValueObservation> observationResults = (batchReadState[YearValueObservationName] as IQueryable<YearValueObservation>).Where<YearValueObservation>((YearValueObservation obs) => (obs.ParentYearlyFinancialAssessmentId == this.Key));
            List<YearValueObservation> observationList = new List<YearValueObservation>(observationResults);
            this.EF_YearlyObservations = observationList;
        }

        private void LoadNestedBatchReadState(DbContext context, object rootQueryPredicate, Dictionary<string, object> batchReadState)
        {
            if (batchReadState.ContainsKey(YearValueObservationName))
            { return; }

            string yearlyAssessmentName = (typeof(YearlyFinancialAssessment)).Name;
            IEnumerable<YearlyFinancialAssessment> yearlyAssessments = batchReadState[yearlyAssessmentName] as IEnumerable<YearlyFinancialAssessment>;
            IEnumerable<Guid> yearlyAssessmentGuids = yearlyAssessments.Select((YearlyFinancialAssessment yfa) => yfa.EF_Key);

            Expression<Func<YearValueObservation, bool>> observationPredicate = null;
            observationPredicate = ((YearValueObservation yso) => yearlyAssessmentGuids.Contains(yso.ParentYearlyFinancialAssessmentId));
            IQueryable<YearValueObservation> observationResults = context.Set<YearValueObservation>().Where(observationPredicate);
            batchReadState.Add(YearValueObservationName, observationResults);
        }

        public void AddNestedAggregateValues(DbContext context)
        {
            Expression<Func<ICollection<YearValueObservation>>> nestedObjectsGetterExpression = () => this.EF_YearlyObservations;
            EfAggregateUtilities.AddNestedValues<YearValueObservation>(context, nestedObjectsGetterExpression);
        }

        public void UpdateNestedAggregateValues(DbContext context, YearlyFinancialAssessment originalAggregate)
        {
            Expression<Func<YearValueObservation, int>> keyGetterExpression = (YearValueObservation nestedObj) => nestedObj.Year;
            Expression<Func<YearValueObservation, YearValueObservation, bool>> nestedObjectsMatchExpression = (YearValueObservation obj1, YearValueObservation obj2) => ((obj1.ParentYearlyFinancialAssessmentId == obj2.ParentYearlyFinancialAssessmentId) && (obj1.Year == obj2.Year));
            Expression<Func<YearlyFinancialAssessment, IDictionary<int, YearValueObservation>>> dictionaryGetterExpression = (YearlyFinancialAssessment agg) => agg.m_YearlyObservations;
            EfAggregateUtilities.UpdateNestedValues<YearlyFinancialAssessment, int, YearValueObservation>(context, this, originalAggregate, keyGetterExpression, nestedObjectsMatchExpression, dictionaryGetterExpression);
        }

        public void DeleteNestedAggregateValues(DbContext context)
        {
            Expression<Func<YearValueObservation, bool>> obsDeleteQueryExpression = ((YearValueObservation obs) => ((obs.ParentYearlyFinancialAssessmentId == this.Key)));
            EfAggregateUtilities.DeleteNestedValues(context, obsDeleteQueryExpression);
        }

        #endregion

        #region AutomotivePricingDataSet Serialization

        private static bool s_IsAggregateRoot = false;
        public static bool IsAggregateRoot
        {
            get { return s_IsAggregateRoot; }
            set { s_IsAggregateRoot = value; }
        }

        public string ObjectTableName
        {
            get { return YearlyFinancialAssessmentsDataSet.SchemaHelper.YearlyFinancialAssessments.TableName; }
        }

        public string KeyColumnName
        {
            get { return YearlyFinancialAssessmentsDataSet.SchemaHelper.YearlyFinancialAssessments.YearlyFinancialAssessmentIdColumn.ColumnName; }
        }

        private string MissingValueOptionColumnName
        {
            get { return YearlyFinancialAssessmentsDataSet.SchemaHelper.YearlyFinancialAssessments.MissingValueOptionIdColumn.ColumnName; }
        }

        private string ObservationTableName
        {
            get { return YearlyFinancialAssessmentsDataSet.SchemaHelper.YearValueObservations.TableName; }
        }

        private string ParentIdColumnName
        {
            get { return YearlyFinancialAssessmentsDataSet.SchemaHelper.YearValueObservations.ParentIdColumn.ColumnName; }
        }

        public void Serialize(DataSet dataSet, DataRow dataRow)
        {
            dataRow[KeyColumnName] = m_Key;
            dataRow[MissingValueOptionColumnName] = (int)m_MissingValueOption;

            //if (!IsAggregateRoot)
            //{
            //    if (dataSet.Tables[ObjectTableName] != dataRow.Table)
            //    { dataSet.Tables[ObjectTableName].Rows.Add(dataRow); }
            //}

            if (!IsAggregateRoot)
            {
                if (!dataSet.Tables[ObjectTableName].Rows.Contains(dataRow))
                { dataSet.Tables[ObjectTableName].Rows.Add(dataRow); }
            }

            DataTable observationDataTable = dataSet.Tables[ObservationTableName];
            foreach (YearValueObservation observation in m_YearlyObservations.Values)
            {
                DataRow observationDataRow = observationDataTable.NewRow();
                observation.Serialize(dataSet, observationDataRow);
            }
        }

        public void Deserialize(DataSet dataSet, DataRow dataRow)
        {
            m_Key = (Guid)dataRow[KeyColumnName];
            m_MissingValueOption = (MissingValueOptionEnum)dataRow[MissingValueOptionColumnName];

            m_YearlyObservations.Clear();
            DataTable observationDataTable = dataSet.Tables[ObservationTableName];
            string queryExpression = string.Format("{0} = '{1}'", ParentIdColumnName, m_Key);
            foreach (DataRow observationDataRow in observationDataTable.Select(queryExpression))
            {
                YearValueObservation observation = new YearValueObservation();
                observation.Deserialize(dataSet, observationDataRow);
                m_YearlyObservations.Add(observation.Year, observation);
            }
        }

        #endregion
    }
}